package com.wjjun.base.data.respository;

import com.google.gson.Gson;
import com.wjjun.base.data.cache.CacheProviders;
import com.wjjun.base.ui.base.BaseActivity;
import com.wjjun.base.ui.base.BaseFragment;
import com.trello.rxlifecycle2.LifecycleTransformer;
import com.trello.rxlifecycle2.android.ActivityEvent;
import com.trello.rxlifecycle2.android.FragmentEvent;
import com.wjjun.basemvpvm.data.executor.PostExecutionThread;
import com.wjjun.basemvpvm.data.executor.ThreadExecutor;
import com.wjjun.basemvpvm.data.repository.BaseApiRepository;

import java.lang.reflect.Field;
import java.util.List;

import dagger.internal.Preconditions;
import io.reactivex.Observable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MultipartBody;

/**
 * 基础数据仓库，连接api库和数据库，缓存等
 * Created by 67535 on 2018/5/24.
 */
public class BaseDataRepository<ARE extends BaseApiRepository> {
    protected ARE apiRepository;
    private ThreadExecutor threadExecutor;
    private PostExecutionThread postExecutionThread;
    private CompositeDisposable disposables;
    protected CacheProviders cacheProviders;
    protected BaseActivity activity;
    protected BaseFragment fragment;

    public BaseDataRepository(ARE apiRepository, ThreadExecutor threadExecutor,
                              PostExecutionThread postExecutionThread, CacheProviders cacheProviders) {

        this.apiRepository = apiRepository;
        this.threadExecutor = threadExecutor;
        this.postExecutionThread = postExecutionThread;
        this.cacheProviders = cacheProviders;
        this.disposables = new CompositeDisposable();
    }

    public BaseDataRepository bind(BaseActivity activity) {
        this.activity = activity;
        return this;
    }

    public BaseDataRepository bind(BaseFragment fragment) {
        this.fragment = fragment;
        return this;
    }

    @SuppressWarnings("unchecked")
    public void execute(Observable observable, DisposableObserver observer) {
        if (activity == null) {
            if (fragment != null) {
                execute(observable, observer, fragment.bindUntilEvent(FragmentEvent.DESTROY));
            } else {
                execute(observable, observer, null);
            }
        } else {
            execute(observable, observer, activity.bindUntilEvent(ActivityEvent.DESTROY));
        }
    }

    @SuppressWarnings("unchecked")
    public void execute(Observable observable, DisposableObserver observer, LifecycleTransformer lifecycleTransformer) {
        com.bumptech.glide.util.Preconditions.checkNotNull(observer);
        Observable<Object> observable2;
        if (lifecycleTransformer == null) {
            observable2 = observable
                    .subscribeOn(Schedulers.from(threadExecutor))
                    .observeOn(postExecutionThread.getScheduler());
        } else {
            observable2 = observable
                    .subscribeOn(Schedulers.from(threadExecutor))
                    .compose(lifecycleTransformer)
                    .observeOn(postExecutionThread.getScheduler());
        }

        addDisposable(observable2.subscribeWith(observer));
    }


    private void addDisposable(Disposable disposable) {
        Preconditions.checkNotNull(disposable);
        Preconditions.checkNotNull(disposables);
        disposables.add(disposable);
    }

    public void dispose() {
        if (!disposables.isDisposed()) {
            disposables.dispose();
        }
    }


    protected MultipartBody.Builder buildFormDataPart(Object param) {
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        if (param == null) {
            return builder;
        }

        Field[] declaredFields = param.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            try {
                if (field.get(param) == null) {
                    builder = builder.addFormDataPart(field.getName(), "");
                } else {
                    if (field.get(param) instanceof List) {
                        builder = builder.addFormDataPart(field.getName(), new Gson().toJson(field.get(param)));
                    } else {
                        builder = builder.addFormDataPart(field.getName(), field.get(param).toString());
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return builder;
    }
}
